package com.mobvoi.serialport.controller;

import android.text.TextUtils;
import android.util.Log;

import com.mobvoi.serialport.BuildConfig;
import com.mobvoi.serialport.util.Parser;

import java.io.File;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import timber.log.Timber;

public class RosCallbackParser {
    private final String port;
    private final int baudRate;
    private final RosCallback callback;

    private SerialPortParser parser;
    private final ConcurrentLinkedQueue<String> receiveLinkedQueue = new ConcurrentLinkedQueue<>();

    private final ConcurrentLinkedQueue<String> sendLinkedQueue = new ConcurrentLinkedQueue<>();
    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);

    public RosCallbackParser(String port, int baudRate, RosCallback callback) {
        this.port = port;
        this.baudRate = baudRate;
        this.callback = callback;
    }

    public void startListen() throws Exception {
        scheduledExecutorService.scheduleWithFixedDelay(resultRunnable, 10, 10, TimeUnit.MILLISECONDS);
        scheduledExecutorService.scheduleWithFixedDelay(sendRunnable, 50, 50, TimeUnit.MILLISECONDS);
        parser = new SerialPortParser(new File(this.port), this.baudRate, (bytes, len) -> {
            String recv_hexstr=Parser.byteArrToHex(bytes, len);
            //sb.append(Parser.byteArrToHex(bytes, len));
            Log.d("uartservice","s5 recv:"+recv_hexstr+" len:"+len);
            receiveLinkedQueue.offer(recv_hexstr);

        });
        Log.d("uartservice","s5 cb start listen parser="+parser);
        parser.start();
    }

    public void stopListen() {
        if (scheduledExecutorService != null) {
            try {
                scheduledExecutorService.shutdownNow();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            scheduledExecutorService = null;
        }
        if (parser != null) {
            parser.stop();
            parser = null;
        }
    }

    public void sendCommand(String hexstr) {
        try {
            if(parser==null)
            {
                Log.d("uartservice","s5 cbparser is null");
            }
            parser.sendCommand(Parser.parseHexStringToBytes(hexstr));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void sendCommandToQueue(String hexstr) {
        sendLinkedQueue.offer(hexstr);
    }

    public static class Builder {
        private String port;
        private int baudRate;
        private RosCallback callback;

        public Builder port(String port) {
            this.port = port;
            return this;
        }

        public Builder baudRate(int baudRate) {
            this.baudRate = baudRate;
            return this;
        }

        public Builder callback(RosCallback callback) {
            this.callback = callback;
            return this;
        }

        public RosCallbackParser build() {
            return new RosCallbackParser(port, baudRate, callback);
        }
    }

    public interface RosCallback {
        void onResult(String result_hexstr);
    }

    Runnable sendRunnable = new Runnable() {
        @Override
        public void run() {
            if (!sendLinkedQueue.isEmpty()) {
                String poll = sendLinkedQueue.poll();
                if (poll != null && !TextUtils.isEmpty(poll)) {
                    //sendCommand(poll);
                    try {
                        parser.sendCommand(Parser.parseHexStringToBytes(poll));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    };

    Runnable resultRunnable = new Runnable() {
        @Override
        public void run() {
            if (callback == null) return;
            try {
                String result = receiveLinkedQueue.poll();
                if (result != null && !TextUtils.isEmpty(result)) {
                    if (receiveLinkedQueue.size() > 10) {
                        //Timber.tag(BuildConfig.LOG_ROS).e("队列数据量过大 : %s", receiveLinkedQueue);
                    }
                    callback.onResult(result);
                }
            } catch (Exception e) {

            }
        }
    };
}
